
package com.hlkj.pay.app.merchant.ext.impl.jhpay.util;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.hlkj.pay.app.merchant.ext.impl.jhpay.dto.JhCommonReq;
import com.hlkj.pay.app.merchant.ext.impl.jhpay.dto.JhPayConfig;

import cn.hutool.core.bean.BeanUtil;

/**
 * @author HlpayTeam
 * @date 2024/12/12 16:28
 */
public class JhPaySignUtil {
    private static Logger logger = LoggerFactory.getLogger(JhPaySignUtil.class);

    public static String signature(JhCommonReq jhCommonReq, JhPayConfig jhPayConfig){
        Map<String, Object> map = BeanUtil.beanToMap(jhCommonReq, true, true);
        String data = sortMapToString(map);
        return sign(data,jhPayConfig.getPrivateKey());
    }
    /**
     * 加密方法
     * 
     * @param data
     *            待加密的数据
     * @param key
     *            密钥
     * @return 加密后的数据（Base64编码）
     */
    public static String encrypt(String data, String key) {
        try {
            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, key.substring(0, 16).getBytes()); // 初始化向量IV
            cipher.init(Cipher.ENCRYPT_MODE, skey, gcmParameterSpec);
            byte[] encryptedData = cipher.doFinal(data.getBytes());
            byte[] iv = cipher.getIV();
            return Base64.getEncoder().encodeToString(iv) + ":" + Base64.getEncoder().encodeToString(encryptedData);
        }
        catch (Exception e) {
            logger.error("AES encrypt error:", e);
            return null;
        }
    }
    /**
     * 解密方法
     * @param encryptedData 待解密的数据（Base64编码）
     * @param key  密钥
     * @return 解密后的数据
     */
    public static String decrypt(String encryptedData, String key) {
        try {
            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
            String[] parts = encryptedData.split(":");
            byte[] iv = Base64.getDecoder().decode(parts[0]);
            byte[] encryptedDataBytes = Base64.getDecoder().decode(parts[1]);
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv);
            cipher.init(Cipher.DECRYPT_MODE, skey, gcmParameterSpec);
            byte[] original = cipher.doFinal(encryptedDataBytes);
            return new String(original);
        } catch (Exception e) {
            logger.error("AES decrypt error:", e);
            return null;
        }
    }
    /**
     * 参数拼接
     * @param paramMap 原数据
     * @return 拼接后的字符串
     */
    public static String sortMapToString(Map<String, Object> paramMap) {
        StringBuilder result = new StringBuilder();
        Collection<String> keySet = paramMap.keySet();
        List<String> list = new ArrayList<>(keySet);
        Collections.sort(list);
        for (String key : list) {
            if ("signature".equals(key)) {
                continue;
            }
            if (paramMap.get(key)!=null&&StringUtils.hasText(paramMap.get(key).toString())) {
                result.append(key).append("=").append(paramMap.get(key)).append("&");
            }
        }
        return result.substring(0, result.length() - 1);
    }
    /**
     * 签名方法
     * @param content 待签名内容
     * @param privateKey 私钥
     * @return 签名后数据(base64)
     */
    public static String sign(String content, String privateKey) {
        try {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey.getBytes()));
            KeyFactory factory = KeyFactory.getInstance("RSA");
            PrivateKey priKey = factory.generatePrivate(priPKCS8);
            Signature signature = Signature.getInstance("SHA256WithRSA");
            signature.initSign(priKey);
            signature.update(content.getBytes("UTF-8"));
            byte[] signed = signature.sign();
            return Base64.getEncoder().encodeToString(signed);
        } catch (Exception e) {
            logger.error("sign error", e);
        }
        return null;
    }
    /**
     * 验证签名
     * @param content 待验签字符串
     * @param sign 签名
     * @param publicKey 公钥
     * @return 验证结果
     */
    public static boolean verify(String content, String sign, String publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey)));
            Signature signature = Signature.getInstance("SHA256WithRSA");
            signature.initVerify(pubKey);
            signature.update(content.getBytes("UTF-8"));
            return signature.verify(Base64.getDecoder().decode(sign));
        } catch (Exception e) {
            logger.error("sign error", e);
        }
        return false;
    }
}
